package org.wheel.plugins.toolkit.sql.entity;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.Getter;
import org.wheel.plugins.toolkit.sql.helper.FieldMeta;
import org.wheel.plugins.toolkit.sql.spi.register.FieldRoleRegistry;
import org.wheel.plugins.toolkit.sql.spi.register.AnnotationRegistry;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 实体元数据缓存 – 单例
 * BeanMeta.java – 实体 ↔ 表名 ↔ 列名 缓存（Hutool 版）
 */
public final class BeanMeta {

    private static final Map<Class<?>, BeanMeta> CACHE = new ConcurrentHashMap<>();

    @Getter
    private final String tableName;
    @Getter
    private final String schema;
    @Getter
    private final List<FieldMeta> fields;
    /**
     * 字段缓存,key为列名，value为字段元数据
     */
    private final Map<String, FieldMeta> fieldMap;

    private BeanMeta(Class<?> clazz) {
        /* 1. 表名：不再直接拿 Table.class，而是走注册中心 */
        this.tableName = AnnotationRegistry.findTable(clazz)
                .map(at -> StrUtil.blankToDefault(at.value(),
                        StrUtil.toUnderlineCase(clazz.getSimpleName())))
                .orElse(StrUtil.toUnderlineCase(clazz.getSimpleName()));

        this.schema = AnnotationRegistry.findTable(clazz)
                .map(at -> StrUtil.blankToDefault(at.schema(), null))
                .orElse(null);
        this.fields = CollUtil.newArrayList();
        for (Field f : ReflectUtil.getFields(clazz)) {
            if("serialVersionUID".equals(f.getName())){
                continue;
            }
            fields.add(new FieldMeta(f));
        }

        this.fieldMap = this.fields.stream().collect(Collectors.toMap(FieldMeta::getColumn, v -> v));
        detectFieldRoles(this.fieldMap);   // ✅ 新增：角色识别
    }

    public static BeanMeta of(Class<?> clazz) {
        return CACHE.computeIfAbsent(clazz, BeanMeta::new);
    }

    /**
     * 获取主键字段元数据
     */
    public FieldMeta getKeyField() {
        return fields.stream().filter(FieldMeta::isPrimaryKey).findFirst().orElse(null);
    }

    /**
     * 通过属性名称，获取字段元数据
     */
    public FieldMeta getField(String fieldName) {
        return fields.stream().filter(f -> f.getFieldName().equals(fieldName))
                .findFirst()
                .orElse(null);
    }

    /**
     * 工具方法：直接返回 “schema.table” 或单表名
     */
    public String getFullTableName() {
        return schema == null ? tableName : schema + "." + tableName;
    }
    /** ✅ 新增：一次性注入角色 */
    private void detectFieldRoles(Map<String, FieldMeta> fieldMap) {
        FieldRoleRegistry.assignRoles(fieldMap); // 2. 再注入角色
    }

    /* ---------- 对外快捷方法 ---------- */
    public boolean hasLogicDelete() {
        return fieldMap.values().stream().anyMatch(FieldMeta::isLogicDelete);
    }
    public boolean hasCreateBy() {
        return fieldMap.values().stream().anyMatch(FieldMeta::isCreateBy);
    }
    public boolean hasCreateTime() {
        return fieldMap.values().stream().anyMatch(FieldMeta::isCreateTime);
    }
    public boolean hasUpdateBy() {
        return fieldMap.values().stream().anyMatch(FieldMeta::isUpdateBy);
    }
    public boolean hasUpdateTime() {
        return fieldMap.values().stream().anyMatch(FieldMeta::isUpdateTime);
    }
    public boolean hasVersion() {
        return fieldMap.values().stream().anyMatch(FieldMeta::isVersion);
    }
    public boolean hasTenantId() {
        return fieldMap.values().stream().anyMatch(FieldMeta::isTenantId);
    }
    public boolean hasDisplayStatus() {
        return fieldMap.values().stream().anyMatch(FieldMeta::isDisplayStatus);
    }
    public FieldMeta getLogicDeleteField() {
        return fieldMap.values().stream()
                .filter(FieldMeta::isLogicDelete)
                .findFirst()
                .orElse(null);
    }
    public FieldMeta getCreateByField() {
        return fieldMap.values().stream()
                .filter(FieldMeta::isCreateBy)
                .findFirst()
                .orElse(null);
    }
    public FieldMeta getCreateTimeField() {
        return fieldMap.values().stream()
                .filter(FieldMeta::isCreateTime)
                .findFirst()
                .orElse(null);
    }
    public FieldMeta getUpdateByField() {
        return fieldMap.values().stream()
                .filter(FieldMeta::isUpdateBy)
                .findFirst()
                .orElse(null);
    }
    public FieldMeta getUpdateTimeField() {
        return fieldMap.values().stream()
                .filter(FieldMeta::isUpdateTime)
                .findFirst()
                .orElse(null);
    }
    public FieldMeta getVersion() {
        return fieldMap.values().stream()
                .filter(FieldMeta::isVersion)
                .findFirst()
                .orElse(null);
    }
    public FieldMeta getDisplayStatusField() {
        return fieldMap.values().stream()
                .filter(FieldMeta::isDisplayStatus)
                .findFirst()
                .orElse(null);
    }
    public FieldMeta getTenantIdField() {
        return fieldMap.values().stream()
                .filter(FieldMeta::isTenantId)
                .findFirst()
                .orElse(null);
    }
}